package co.baiku.boot.office;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.util.Map.Entry;

/**
 * @Author wushuaifei
 * @Date 2020/10/23 14:46
 */
public class Word {

    private static Logger log = LoggerFactory.getLogger(Word.class);


        /**
         * 输出文件
         * @param doc
         * @param outPath
         */
        private static void saveDoc(HWPFDocument doc,String outPath){
            FileOutputStream out = null;
            try {
                out = new FileOutputStream(new File(outPath));
                doc.write(out);
            } catch (Exception e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }finally{
                if(out != null){
                    try {
                        out.close();
                    } catch (IOException e) {
                        // TODO 自動生成された catch ブロック
                        e.printStackTrace();
                    }
                }
            }
        }
        /**
         根据代码的code，格式化输出数据
         * @param file
         * @param map
         * @return
         * @throws IOException
         * @throws FileNotFoundException
         */
        private static HWPFDocument createTemplateDoc(String file, Map<String, String> map) throws IOException,
                FileNotFoundException {
            //获取到文档
            HWPFDocument doc = new HWPFDocument(new FileInputStream(file));
            Range range = doc.getRange();
            //查看段落数量
            int paraNum = range.numParagraphs();
            for(int i=0;i<paraNum;i++){
                //获取段落
                Paragraph paragraph =range.getParagraph(i);
                if(paragraph.text().indexOf("$")>-1){
                    for(Map.Entry<String, String> entry:map.entrySet()){
                        paragraph.replaceText(entry.getKey(), entry.getValue());
                    }
                }
            }
            return doc;
        }

        /**
         * 根据模板生成新word文档
         * 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
         * @param inputUrl 模板存放地址
         * @param outputUrl 新文档存放地址
         * @param textMap 需要替换的信息集合
//         * @param tableList 需要插入的表格信息集合
         * @return 成功返回true,失败返回false
         */
        public static boolean changWord(String inputUrl, String outputUrl,
                                        Map<String, String> textMap) {
            //, List<String[]> tableList
            //模板转换默认成功
            boolean changeFlag = true;
            try {
                //获取docx解析对象
                XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
                //解析替换文本段落对象
                changeText(document, textMap);
                //解析替换表格对象
                //changeTable(document, textMap, tableList);

                //生成新的word
                File file = new File(outputUrl);
                FileOutputStream stream = new FileOutputStream(file);
                document.write(stream);
                stream.close();

            } catch (IOException e) {
                e.printStackTrace();
                changeFlag = false;
            }

            return changeFlag;

        }

    public static boolean changWord(String inputUrl, String outputUrl,
                                    Map<String, String> textMap, List<String[]> tableList) {
        //模板转换默认成功
        boolean changeFlag = true;
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            changeText(document, textMap);
            //解析替换表格对象
            changeTable(document, textMap, tableList);

            //生成新的word
            File file = new File(outputUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();

        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }

        return changeFlag;

    }
        /**
         * 替换段落文本
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         */
        public static void changeText(XWPFDocument document, Map<String, String> textMap){
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();

            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落时候需要进行替换
                String text = paragraph.getText();
                if(checkText(text)){
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        //替换模板原来位置
                        run.setText(changeValue(run.toString(), textMap),0);
                    }
                }
            }

        }

        /**
         * 替换表格对象方法
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         * @param tableList 需要插入的表格信息集合
         */
        public static void changeTable(XWPFDocument document, Map<String, String> textMap,
                                       List<String[]> tableList){
            //获取表格对象集合
            List<XWPFTable> tables = document.getTables();
            for (int i = 0; i < tables.size(); i++) {
                //只处理行数大于等于2的表格，且不循环表头
                XWPFTable table = tables.get(i);
                if(table.getRows().size()>1){
                    //判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
                    if(checkText(table.getText())){
                        List<XWPFTableRow> rows = table.getRows();
                        //遍历表格,并替换模板
                        eachTable(rows, textMap);
                    }else{
                        insertTable(table, tableList);
                    }
                }
            }
        }





        /**
         * 遍历表格
         * @param rows 表格行对象
         * @param textMap 需要替换的信息集合
         */
        public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    //判断单元格是否需要替换
                    if(checkText(cell.getText())){
                        List<XWPFParagraph> paragraphs = cell.getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            List<XWPFRun> runs = paragraph.getRuns();
                            for (XWPFRun run : runs) {
                                run.setText(changeValue(run.toString(), textMap),0);
                            }
                        }
                    }
                }
            }
        }

        /**
         * 为表格插入数据，行数不够添加新行
         * @param table 需要插入数据的表格
         * @param tableList 插入数据集合
         */
        public static void insertTable(XWPFTable table, List<String[]> tableList){
            //创建行,根据需要插入的数据添加新行，不处理表头
            for(int i = 1; i < tableList.size(); i++){
                XWPFTableRow row =table.createRow();
            }
            //遍历表格插入数据
            List<XWPFTableRow> rows = table.getRows();
            for(int i = 1; i < rows.size(); i++){
                XWPFTableRow newRow = table.getRow(i);
                List<XWPFTableCell> cells = newRow.getTableCells();
                for(int j = 0; j < cells.size(); j++){
                    XWPFTableCell cell = cells.get(j);
                    cell.setText(tableList.get(i-1)[j]);
                }
            }

        }



        /**
         * 判断文本中时候包含$
         * @param text 文本
         * @return 包含返回true,不包含返回false
         */
        public static boolean checkText(String text){
            boolean check  =  false;
            if(text.indexOf("$")!= -1){
                check = true;
            }
            return check;

        }

        /**
         * 匹配传入信息集合与模板
         * @param value 模板需要替换的区域
         * @param textMap 传入信息集合
         * @return 模板需要替换区域信息集合对应值
         */
        public static String changeValue(String value, Map<String, String> textMap){
            Set<Entry<String, String>> textSets = textMap.entrySet();
            for (Entry<String, String> textSet : textSets) {
                //匹配模板与替换值 格式${key}
                String key = "${"+textSet.getKey()+"}";
                if(value.indexOf(key)!= -1){
                    value = textSet.getValue();
                }
            }
            //模板未匹配到区域替换为空
            if(checkText(value)){
                value = "";
            }
            return value;
        }


    public static void main(String[] args) throws Exception{
        //模板文件地址
        String inputUrl = "/Users/wushuaifei/Downloads/test1.docx";
        //新生产的模板文件
        String outputUrl = "/Users/wushuaifei/Downloads/test2.docx";
        if(inputUrl.endsWith("docx")){
            Map<String, String> testMap = new HashMap<String, String>();
            testMap.put("1001", "全国人大常委会");
            testMap.put("1002", "2020.08.01");
            testMap.put("1003", "尚未生效");
            testMap.put("1004", "城市维护建设税");
            testMap.put("1005", "中国人民共和国主席令第51号");
            testMap.put("1006", "法律");
            List<String[]> testList = new ArrayList<String[]>();
            testList.add(new String[]{"全国人大常委会","2020.08.01","尚未生效"});
            testList.add(new String[]{"城市维护建设税","中国人民共和国主席令第51号","法律"});
            Word.changWord(inputUrl, outputUrl, testMap,testList);
        }else if(inputUrl.endsWith("doc")){
            Map<String, String> testMap = new HashMap<String, String>();
            testMap.put("title", "哈哈");
            testMap.put("name", "张三");
            testMap.put("url", "127.0.0.1");
            //获取修改模版后的代码
            HWPFDocument doc = createTemplateDoc(inputUrl , testMap );
            //保存doc文件
            saveDoc(doc, outputUrl);
        }
    }

}
